/*
 * This file is part of Cadmium.
 * Copyright (C) 2007-2010 Xavier Clerc.
 *
 * Cadmium is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Cadmium is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package fr.x9c.cadmium.primitives.stdlib;

import fr.x9c.cadmium.kernel.Block;
import fr.x9c.cadmium.kernel.CodeRunner;
import fr.x9c.cadmium.kernel.Context;
import fr.x9c.cadmium.kernel.Primitive;
import fr.x9c.cadmium.kernel.PrimitiveProvider;
import fr.x9c.cadmium.kernel.Value;

/**
 * Implements all primitives from 'gc_ctrl.c'.
 *
 * @author <a href="mailto:cadmium@x9c.fr">Xavier Clerc</a>
 * @version 1.2
 * @since 1.0
 */
@PrimitiveProvider
public final class Gc_ctrl {

    /**
     * No instance of this class.
     */
    private Gc_ctrl() {
    } // end empty constructor

    /**
     * Exact synonym of {@link #caml_gc_quick_stat(CodeRunner, Value)}.
     * @param ctxt context
     * @param unit ignored
     * @return memory statistics
     */
    @Primitive
    public static Value caml_gc_stat(final CodeRunner ctxt,
                                     final Value unit) {
        return caml_gc_quick_stat(ctxt, unit);
    } // end method 'caml_gc_stat(CodeRunner, Value)'

    /**
     * Returns the memory statistics.
     * @param ctxt context
     * @param unit ignored
     * @return memory statistics
     */
    @Primitive
    public static Value caml_gc_quick_stat(final CodeRunner ctxt,
                                           final Value unit) {
        return ctxt.getContext().gcStats();
    } // end method 'caml_gc_quick_stat(CodeRunner, Value)'

    /**
     * Returns the memory statistics.
     * @param ctxt context
     * @param unit ignored
     * @return memory statistics
     */
    @Primitive
    public static Value caml_gc_counters(final CodeRunner ctxt,
                                         final Value unit) {
        return ctxt.getContext().gcCounters();
    } // end method 'caml_gc_counters(CodeRunner, Value)'

    /**
     * Returns the garbage collector parameters. <br/>
     * These parameters are stored but ignored as garbage collection is done
     * by the JVM.
     * @param ctxt context
     * @param unit ignored
     * @return <i>(a, b, c, d, e, f, g)</i> where: <br/>
     *         <ul>
     *           <li><i>a</i> is the size of the minor heap;</li>
     *           <li><i>b</i> is the major heap increment;</li>
     *           <li><i>c</i> is the space overhead;</li>
     *           <li><i>d</i> is the verbosity level;</li>
     *           <li><i>e</i> is the maximum overhead;</li>
     *           <li><i>f</i> is the stack limit;</li>
     *           <li><i>g</i> is the allocation policy.</li>
     *         </ul>
     */
    @Primitive
    public static Value caml_gc_get(final CodeRunner ctxt,
                                    final Value unit) {
        return ctxt.getContext().makeGcParams();
    } // end method 'caml_gc_get(CodeRunner, Value)'

    /**
     * Changes the garbage collector parameters. <br/>
     * These parameters are stored but ignored as garbage collection is done
     * by the JVM.
     * @param ctxt context
     * @param params <i>(a, b, c, d, e, f, g)</i> where: <br/>
     *               <ul>
     *                 <li><i>a</i> is the size of the minor heap;</li>
     *                 <li><i>b</i> is the major heap increment;</li>
     *                 <li><i>c</i> is the space overhead;</li>
     *                 <li><i>d</i> is the verbosity level;</li>
     *                 <li><i>e</i> is the maximum overhead;</li>
     *                 <li><i>f</i> is the stack limit;</li>
     *                 <li><i>g</i> is the allocation policy.</li>
     *               </ul>
     * @return <i>unit</i>
     */
    @Primitive
    public static Value caml_gc_set(final CodeRunner ctxt,
                                    final Value params) {
        final Block p = params.asBlock();
        ctxt.getContext().setGcParams(p.get(0).asLong(),
                                      p.get(1).asLong(),
                                      p.get(2).asLong(),
                                      p.get(3).asLong(),
                                      p.get(4).asLong(),
                                      p.get(5).asLong(),
                                      p.get(6).asLong());
        return Value.UNIT;
    } // end method 'caml_gc_set(CodeRunner, Value)'

    /**
     * Exact synonym of {@link #caml_gc_full_major(CodeRunner, Value)},
     * except that counters are not incremented the same way.
     * @param ctxt context
     * @param unit ignored
     * @return <i>unit</i>
     */
    @Primitive
    public static Value caml_gc_minor(final CodeRunner ctxt,
                                      final Value unit) {
        gc(ctxt.getContext());
        ctxt.getContext().incMinorCounter();
        return Value.UNIT;
    } // end method 'caml_gc_minor(CodeRunner, Value)'

    /**
     * Exact synonym of {@link #caml_gc_full_major(CodeRunner, Value)},
     * except that counters are not incremented the same way.
     * @param ctxt context
     * @param unit ignored
     * @return <i>unit</i>
     */
    @Primitive
    public static Value caml_gc_major(final CodeRunner ctxt,
                                      final Value unit) {
        gc(ctxt.getContext());
        ctxt.getContext().incMajorCounter();
        return Value.UNIT;
    } // end method 'caml_gc_major(CodeRunner, Value)'

    /**
     * Performs a garbage collection and recycles block and value instances
     * (and thus calls registered finalizers).
     * @param ctxt context
     * @param unit ignored
     * @return <i>unit</i>
     */
    @Primitive
    public static Value caml_gc_full_major(final CodeRunner ctxt,
                                           final Value unit) {
        gc(ctxt.getContext());
        ctxt.getContext().incMajorCounter();
        return Value.UNIT;
    } // end method 'caml_gc_full_major(CodeRunner, Value)'

    /**
     * Exact synonym of {@link #caml_gc_full_major(CodeRunner, Value)}.
     * @param ctxt context
     * @param unit ignored
     * @return <i>unit</i>
     */
    @Primitive
    public static Value caml_gc_major_slice(final CodeRunner ctxt,
                                            final Value unit) {
        gc(ctxt.getContext());
        ctxt.getContext().incMajorCounter();
        return Value.UNIT;
    } // end method 'caml_gc_major_slice(CodeRunner, Value)'

    /**
     * Exact synonym of {@link #caml_gc_full_major(CodeRunner, Value)}.
     * @param ctxt context
     * @param unit ignored
     * @return <i>unit</i>
     */
    @Primitive
    public static Value caml_gc_compaction(final CodeRunner ctxt,
                                           final Value unit) {
        gc(ctxt.getContext());
        ctxt.getContext().incCompactionCounter();
        return Value.UNIT;
    } // end method 'caml_gc_compaction(CodeRunner, Value)'

    /**
     * Asks for JVM garbage collection.
     * @param ctxt context
     */
    private static void gc(final Context ctxt) {
        assert ctxt != null : "null ctxt";
        System.gc();
    } // end method 'gc()'

} // end class 'Gc_ctrl'
